home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / os2 / raytrace / dkb / os2port.exe / DKB212O2.ZIP / TRACE.C < prev   
Encoding:
C/C++ Source or Header  |  1991-07-04  |  19.0 KB  |  658 lines

  1. /*****************************************************************************
  2. *
  3. *                                     trace.c
  4. *
  5. *   from DKBTrace (c) 1990  David Buck
  6. *
  7. *  This module contains the entry routine for the raytracer and the code to
  8. *  parse the parameters on the command line.
  9. *
  10. *
  11. * This software is freely distributable. The source and/or object code may be
  12. * copied or uploaded to communications services so long as this notice remains
  13. * at the top of each file.  If any changes are made to the program, you must
  14. * clearly indicate in the documentation and in the programs startup message
  15. * who it was who made the changes. The documentation should also describe what
  16. * those changes were. This software may not be included in whole or in
  17. * part into any commercial package without the express written consent of the
  18. * author.  It may, however, be included in other public domain or freely
  19. * distributed software so long as the proper credit for the software is given.
  20. *
  21. * This software is provided as is without any guarantees or warranty. Although
  22. * the author has attempted to find and correct any bugs in the software, he
  23. * is not responsible for any damage caused by the use of the software.  The
  24. * author is under no obligation to provide service, corrections, or upgrades
  25. * to this package.
  26. *
  27. * Despite all the legal stuff above, if you do find bugs, I would like to hear
  28. * about them.  Also, if you have any comments or questions, you may contact me
  29. * at the following address:
  30. *
  31. *     David Buck
  32. *     22C Sonnet Cres.
  33. *     Nepean Ontario
  34. *     Canada, K2H 8W7
  35. *
  36. *  I can also be reached on the following bulleton boards:
  37. *
  38. *     OMX              (613) 731-3419
  39. *     Mystic           (613) 596-4249  or  (613) 596-4772
  40. *
  41. *  Fidonet:   1:163/109.9
  42. *  Internet:  dbuck@ccs.carleton.ca
  43. *  The "You Can Call Me RAY" BBS    (708) 358-5611
  44. *
  45. *  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
  46. *
  47. *     The "You Can Call Me RAY" BBS (708) 358-5611
  48. *     The Information Exchange BBS  (708) 945-5575
  49. *
  50. *****************************************************************************/
  51.  
  52. /* define DosSetPrty function (Set Priority) */
  53. #include <os2.h>
  54. USHORT APIENTRY DosSetPrty(USHORT usScope, USHORT fPrtyClass, SHORT sChange,
  55.                            USHORT id);
  56.  
  57. #include <ctype.h>
  58. #include "frame.h"        /* common to ALL modules in this program */
  59. #include "dkbproto.h"
  60.  
  61. #define MAX_FILE_NAMES 1
  62. unsigned int Options;
  63. int Quality;
  64.  
  65. FILE *bfp;
  66.  
  67. extern FRAME Frame;
  68.  
  69. char Input_File_Name[FILE_NAME_LENGTH], Output_File_Name[FILE_NAME_LENGTH];
  70.  
  71. #define MAX_LIBRARIES 10
  72. char *Library_Paths[MAX_LIBRARIES];
  73. int Library_Path_Index;
  74.  
  75. FILE_HANDLE *Output_File_Handle;
  76. int File_Buffer_Size;
  77. static int Number_Of_Files;
  78. DBL VTemp;
  79. DBL Antialias_Threshold;
  80. int First_Line, Last_Line;
  81. int Display_Started = FALSE;
  82.  
  83. /* Stats kept by the ray tracer: */
  84. long Number_Of_Pixels, Number_Of_Rays, Number_Of_Pixels_Supersampled;
  85. long Ray_Sphere_Tests, Ray_Sphere_Tests_Succeeded;
  86. long Ray_Plane_Tests, Ray_Plane_Tests_Succeeded;
  87. long Ray_Triangle_Tests, Ray_Triangle_Tests_Succeeded;
  88. long Ray_Quadric_Tests, Ray_Quadric_Tests_Succeeded;
  89. long Ray_Quartic_Tests, Ray_Quartic_Tests_Succeeded;
  90. long Bounding_Region_Tests, Bounding_Region_Tests_Succeeded;
  91. long Calls_To_Noise, Calls_To_DNoise;
  92. long Shadow_Ray_Tests, Shadow_Rays_Succeeded;
  93. long Reflected_Rays_Traced, Refracted_Rays_Traced;
  94. long Transmitted_Rays_Traced;
  95.  
  96. char DisplayFormat, OutputFormat;
  97.  
  98. void main (argc, argv)
  99.   int argc;
  100.   char **argv;
  101.   {
  102.   register int i;
  103.  
  104.   STARTUP_DKB_TRACE
  105.  
  106.   /* Define DKB as an 'idle time, but high priority' task */
  107.   DosSetPrty(1,1,31,0);
  108.   
  109.   printf ("\n\n          DKB Ray Trace   Version 2.12\n");
  110.   printf ("          ----------------------------\n\n");
  111.   printf ("        Copyright (c) 1991  David K. Buck\n\n");
  112.   printf ("  Written by:\n");
  113.   printf ("  David K. Buck (dbuck@ccs.carleton.ca) (CIS: 70521, 1371)\n");
  114.   printf ("  22C Sonnet Cr.  Nepean, Ontario\n");
  115.   printf ("  Canada, K2H 8W7\n\n");
  116.   printf ("  This program is freely distributable.\n\n");
  117.  
  118.   printf ("  Conversion to IBM P.C. w/TARGA output and\n");
  119.   printf ("  other various improvements by Aaron A. Collins\n\n");
  120.  
  121.   printf ("  GIF format file reader by Steve A. Bennett\n\n");
  122.  
  123.   printf ("  Noise and DNoise functions by Robert Skinner\n\n");
  124.  
  125.   printf ("  Quartic (4th order) Shapes by Alexander Enzmann\n\n");
  126.  
  127.   PRINT_OTHER_CREDITS
  128.  
  129. /* Parse the command line parameters */
  130.   if (argc == 1)
  131.      usage();
  132.  
  133.   init_vars();
  134.  
  135.   Output_File_Name[0]='\0';
  136.  
  137.   Library_Paths[0] = NULL;
  138.   Library_Path_Index = 0;
  139.  
  140. /* Read the default parameters from trace.def */
  141.   get_defaults();
  142.  
  143.   for (i = 1 ; i < argc ; i++ )
  144.     if ((*argv[i] == '+') || (*argv[i] == '-'))
  145.       parse_option(argv[i]);
  146.     else
  147.       parse_file_name(argv[i]);
  148.  
  149.    if (Last_Line == -1)
  150.       Last_Line = Frame.Screen_Height;
  151.  
  152.    if (Options & DISKWRITE) {
  153.       switch (OutputFormat) {
  154.          case '\0':
  155.          case 'd':
  156.          case 'D':
  157.                    if ((Output_File_Handle = Get_Dump_File_Handle()) == NULL) {
  158.                       close_all();
  159.                       exit(1);
  160.                       }
  161.                    break;
  162. /*
  163.          case 'i':
  164.          case 'I':
  165.                    if ((Output_File_Handle = Get_Iff_File_Handle()) == NULL) {
  166.                       close_all();
  167.                       exit(1);
  168.                       }
  169.                    break;
  170.  
  171. */
  172.          case 'r':
  173.          case 'R':
  174.                    if ((Output_File_Handle = Get_Raw_File_Handle()) == NULL) {
  175.                       close_all();
  176.                       exit(1);
  177.                       }
  178.                    break;
  179.  
  180.          case 't':
  181.          case 'T':
  182.                    if ((Output_File_Handle = Get_Targa_File_Handle()) == NULL) {
  183.                       close_all();
  184.                       exit(1);
  185.                       }
  186.                    break;
  187.  
  188.          default:
  189.                    fprintf (stderr, "Unrecognized output file format %c\n", OutputFormat);
  190.                    exit(1);
  191.          }
  192.  
  193.       if (Output_File_Name[0] == '\0')
  194.          strcpy (Output_File_Name, Default_File_Name (Output_File_Handle));
  195.       }
  196.  
  197.    Print_Options();
  198.  
  199.    Initialize_Tokenizer(Input_File_Name);
  200.    printf ("Parsing...\n");
  201.    Parse (&Frame);
  202.    Terminate_Tokenizer();
  203.  
  204.   if (Options & DISPLAY)
  205.     {
  206.     printf ("Displaying...\n");
  207.     display_init(Frame.Screen_Width, Frame.Screen_Height);
  208.     Display_Started = TRUE;
  209.     }
  210.  
  211. /* Get things ready for ray tracing */
  212.    if (Options & DISKWRITE)
  213.       if (Options & CONTINUE_TRACE) {
  214.          if (Open_File (Output_File_Handle, Output_File_Name,
  215.                  &Frame.Screen_Width, &Frame.Screen_Height, File_Buffer_Size,
  216.                  READ_MODE) != 1) {
  217.             fprintf (stderr, "Error opening output file\n");
  218.             close_all();
  219.             exit(1);
  220.             }
  221.  
  222.          initialize_renderer();
  223.          Read_Rendered_Part();
  224.          }
  225.       else {
  226.          if (Open_File (Output_File_Handle, Output_File_Name,
  227.                  &Frame.Screen_Width, &Frame.Screen_Height, File_Buffer_Size,
  228.                  WRITE_MODE) != 1) {
  229.             fprintf (stderr, "Error opening output file\n");
  230.             close_all();
  231.             exit(1);
  232.             }
  233.  
  234.          initialize_renderer();
  235.          }
  236.   else
  237.      initialize_renderer();
  238.  
  239.   pq_init();
  240.   Initialize_Noise();
  241.  
  242. /* Ok, go for it - trace the picture */
  243.   if (!(Options & DISPLAY))
  244.       printf ("Rendering...\n");
  245.   Start_Tracing ();
  246.  
  247. /* Wait for a CR if the user requested it. */
  248.  
  249. /* Clean up and leave */
  250.   display_finished();
  251.  
  252.   close_all ();
  253.   print_stats();
  254.  
  255.   FINISH_DKB_TRACE
  256.   }
  257.  
  258. /* Print out usage error message */
  259.  
  260. void usage ()
  261.     {
  262.     printf ("\nUsage:");
  263.     printf ("\n   trace  [+/-] Option1 [+/-] Option2");
  264.     printf ("\n");
  265.     printf ("\n Options:");
  266.     printf ("\n    dx = display in format x");
  267.     printf ("\n    v  = verbose");
  268.     printf ("\n    p  = prompt exit");
  269.     printf ("\n    x  = enable early exit by key hit");
  270.     printf ("\n    fx = write output file in format x");
  271.     printf ("\n         ft - Uncompressed Targa-24  fd - DKB/QRT Dump  fr - 3 Raw Files");
  272.     printf ("\n    a  = perform antialiasing");
  273.     printf ("\n    c  = continue aborted trace");
  274.     printf ("\n    qx = image quality 0=rough, 9=full");
  275.     printf ("\n    lxxx = library path prefix");
  276.     printf ("\n    wxxx = width of the screen");
  277.     printf ("\n    hxxx = height of the screen");
  278.     printf ("\n    sxxx = start at line number xxx");
  279.     printf ("\n    exxx = end at line number xxx");
  280.     printf ("\n    bxxx = Use xxx kilobytes for output file buffer space");
  281.     printf ("\n    ifilename = input file name");
  282.     printf ("\n    ofilename = output file name");
  283.     printf ("\n\n");
  284.     exit(1);
  285.     }
  286.  
  287. void init_vars()
  288.   {
  289.   Output_File_Handle = NULL;
  290.   File_Buffer_Size = 0;
  291.   Options = 0;
  292.   Quality = 9;
  293.   Number_Of_Files = 0;
  294.   First_Line = 0;
  295.   Last_Line = -1;
  296.  
  297.   Number_Of_Pixels = 0L;
  298.   Number_Of_Rays = 0L;
  299.   Number_Of_Pixels_Supersampled = 0L;
  300.   Ray_Sphere_Tests = 0L;
  301.   Ray_Sphere_Tests_Succeeded = 0L;
  302.   Ray_Plane_Tests = 0L;
  303.   Ray_Plane_Tests_Succeeded = 0L;
  304.   Ray_Triangle_Tests = 0L;
  305.   Ray_Triangle_Tests_Succeeded = 0L;
  306.   Ray_Quadric_Tests = 0L;
  307.   Ray_Quadric_Tests_Succeeded = 0L;
  308.   Ray_Quartic_Tests = 0L;
  309.   Ray_Quartic_Tests_Succeeded = 0L;
  310.   Bounding_Region_Tests = 0L;
  311.   Bounding_Region_Tests_Succeeded = 0L;
  312.   Calls_To_Noise = 0L;
  313.   Calls_To_DNoise = 0L;
  314.   Shadow_Ray_Tests = 0L;
  315.   Shadow_Rays_Succeeded = 0L;
  316.   Reflected_Rays_Traced = 0L;
  317.   Refracted_Rays_Traced = 0L;
  318.   Transmitted_Rays_Traced = 0L;
  319.  
  320.   Frame.Screen_Height = 100;
  321.   Frame.Screen_Width = 100;
  322.  
  323.   Antialias_Threshold = 0.3;
  324.   strcpy (Input_File_Name, "object.dat");
  325.   return;
  326.   }
  327.  
  328. /* Close all the stuff that has been opened. */
  329. void close_all ()
  330.    {
  331.    if ((Options & DISPLAY) && Display_Started)
  332.      display_close();
  333.  
  334.    if (Output_File_Handle)
  335.       Close_File (Output_File_Handle);
  336.    }
  337.  
  338. /* Read the default parameters from trace.def*/
  339. void get_defaults()
  340.   {
  341.   FILE *defaults_file;
  342.   char Option_String[256], *Option_String_Ptr;
  343.  
  344.   if ((defaults_file = fopen("trace.def", "r")) != NULL) {
  345.      while (fgets(Option_String, 256, defaults_file) != NULL)
  346.         read_options(Option_String);
  347.      fclose (defaults_file);
  348.      }
  349.  
  350.   if ((Option_String_Ptr = getenv("DKBOPT")) != NULL)
  351.      read_options(Option_String_Ptr);
  352.   }
  353.  
  354. void read_options (Option_Line)
  355.   char *Option_Line;
  356.   {
  357.   register int c, String_Index, Option_Started;
  358.   short Option_Line_Index = 0;
  359.   char Option_String[80];
  360.  
  361.   String_Index = 0;
  362.   Option_Started = FALSE;
  363.   while ((c = Option_Line[Option_Line_Index++]) != '\0')
  364.     {
  365.     if (Option_Started)
  366.       if (isspace(c))
  367.         {
  368.         Option_String[String_Index] = '\0';
  369.         parse_option (Option_String);
  370.         Option_Started = FALSE;
  371.     String_Index = 0;
  372.         }
  373.      else
  374.        Option_String[String_Index++] = (char) c;
  375.  
  376.     else /* Option_Started */
  377.       if ((c == (int) '-') || (c == (int) '+'))
  378.         {
  379.         String_Index = 0;
  380.         Option_String[String_Index++] = (char) c;
  381.         Option_Started = TRUE;
  382.         }
  383.       else
  384.         if (!isspace(c))
  385.           {
  386.           fprintf (stderr, "\nBad default file format.  Offending char: (%c), val: %d.\n", (char) c, c);
  387.           exit (1);
  388.           }
  389.     }
  390.  
  391.   if (Option_Started)
  392.     {
  393.     Option_String[String_Index] = '\0';
  394.     parse_option (Option_String);
  395.     }
  396.   }
  397.  
  398. /* parse the command line parameters */
  399. void parse_option (Option_String)
  400.   char *Option_String;
  401.   {
  402.   register int Add_Option;
  403.   unsigned int Option_Number;
  404.   DBL threshold;
  405.  
  406.   if (*(Option_String++) == '-')
  407.     Add_Option = FALSE;
  408.   else
  409.     Add_Option = TRUE;
  410.  
  411.   switch (*Option_String)
  412.     {
  413.     case 'B':
  414.     case 'b':  sscanf (&Option_String[1], "%d", &File_Buffer_Size);
  415.                File_Buffer_Size *= 1024;
  416.                if (File_Buffer_Size < BUFSIZ)
  417.                   File_Buffer_Size = BUFSIZ;
  418.                Option_Number = 0;
  419.                break;
  420.  
  421.     case 'C':
  422.     case 'c':  Option_Number = CONTINUE_TRACE;
  423.                break;
  424.  
  425.     case 'D':
  426.     case 'd':  Option_Number = DISPLAY;
  427.                DisplayFormat = (char)toupper(Option_String[1]);
  428.                if (DisplayFormat == '\0')
  429.                   DisplayFormat = '0';
  430.                break;
  431.  
  432.     case 'V':
  433.     case 'v':  Option_Number = VERBOSE;
  434.                break;
  435.  
  436.     case 'W':
  437.     case 'w':  sscanf (&Option_String[1], "%d", &Frame.Screen_Width);
  438.            Option_Number = 0;
  439.                break;
  440.  
  441.     case 'H':
  442.     case 'h':  sscanf (&Option_String[1], "%d", &Frame.Screen_Height);
  443.            Option_Number = 0;
  444.                break;
  445.  
  446.     case 'F':
  447.     case 'f':  Option_Number = DISKWRITE;
  448.                if (isupper(Option_String[1]))
  449.                   OutputFormat = (char)tolower(Option_String[1]);
  450.                else
  451.                   OutputFormat = Option_String[1];
  452.  
  453.                /* Default the output format to raw. */
  454.                if (OutputFormat == '\0')
  455.                   OutputFormat = DEFAULT_OUTPUT_FORMAT;
  456.                break;
  457.  
  458.     case 'P':
  459.     case 'p':  Option_Number = PROMPTEXIT;
  460.                break;
  461.  
  462.     case 'I':
  463.     case 'i':  strncpy (Input_File_Name, &Option_String[1], FILE_NAME_LENGTH);
  464.            Option_Number = 0;
  465.                break;
  466.  
  467.     case 'O':
  468.     case 'o':  strncpy (Output_File_Name, &Option_String[1], FILE_NAME_LENGTH);
  469.            Option_Number = 0;
  470.                break;
  471.  
  472.     case 'A':
  473.     case 'a':  Option_Number = ANTIALIAS;
  474.                if (sscanf (&Option_String[1], DBL_FORMAT_STRING, &threshold) != EOF)
  475.                    Antialias_Threshold = threshold;
  476.                break;
  477.  
  478.     case 'X':
  479.     case 'x':  Option_Number = EXITENABLE;
  480.                break;
  481.  
  482.  
  483.     case 'L':
  484.     case 'l':  if (Library_Path_Index >= MAX_LIBRARIES) {
  485.                   fprintf (stderr, "Too many library directories specified\n");
  486.                   exit(1);
  487.                   }
  488.  
  489.                Library_Paths [Library_Path_Index] = malloc (strlen(Option_String));
  490.            if (Library_Paths [Library_Path_Index] == NULL) {
  491.           fprintf (stderr, "Cannot allocate memory for library pathname\n");
  492.           exit(1);
  493.           }
  494.                strcpy (Library_Paths [Library_Path_Index], &Option_String[1]);
  495.                Library_Path_Index++;
  496.            Option_Number = 0;
  497.                break;
  498.  
  499.     case 'S':
  500.     case 's':  sscanf (&Option_String[1], "%d", &First_Line);
  501.            Option_Number = 0;
  502.                break;
  503.  
  504.     case 'E':
  505.     case 'e':  sscanf (&Option_String[1], "%d", &Last_Line);
  506.            Option_Number = 0;
  507.                break;
  508.  
  509.     case 'Q':
  510.     case 'q':  sscanf (&Option_String[1], "%d", &Quality);
  511.            Option_Number = 0;
  512.                break;
  513.  
  514.                /* Turn on debugging print statements. */
  515.     case 'Z':
  516.     case 'z':  Option_Number = DEBUGGING;
  517.                break;
  518.  
  519.     default:   fprintf (stderr, "\nInvalid option: %s\n\n", --Option_String);
  520.            Option_Number = 0;
  521.     }
  522.  
  523.   if (Option_Number != 0)
  524.       if (Add_Option)
  525.            Options |= Option_Number;
  526.       else Options &= ~Option_Number;
  527.   }
  528.  
  529. void Print_Options()
  530.    {
  531.    int i;
  532.  
  533.    printf ("Options in effect: ");
  534.  
  535.    if (Options & CONTINUE_TRACE)
  536.       printf ("+c ");
  537.    else
  538.       printf ("-c ");
  539.  
  540.    if (Options & DISPLAY)
  541.       printf ("+d%c ", DisplayFormat);
  542.    else
  543.       printf ("-d ");
  544.  
  545.    if (Options & VERBOSE)
  546.       printf ("+v ");
  547.    else
  548.       printf ("-v ");
  549.  
  550.    if (Options & DISKWRITE)
  551.       printf ("+f%c ", OutputFormat);
  552.    else
  553.       printf ("-f ");
  554.  
  555.    if (Options & PROMPTEXIT)
  556.       printf ("+p ");
  557.    else
  558.       printf ("-p ");
  559.  
  560.    if (Options & EXITENABLE)
  561.       printf ("+x ");
  562.    else
  563.       printf ("-x ");
  564.  
  565.    if (Options & ANTIALIAS)
  566.       printf ("+a%f ", Antialias_Threshold);
  567.    else
  568.       printf ("-a ");
  569.  
  570.    if (Options & DEBUGGING)
  571.       printf ("+z ");
  572.  
  573.    if (File_Buffer_Size != 0)
  574.       printf ("-b%d ", File_Buffer_Size/1024);
  575.  
  576.    printf ("-q%d -w%d -h%d -s%d -e%d\n-i%s ",
  577.            Quality, Frame.Screen_Width, Frame.Screen_Height,
  578.            First_Line, Last_Line, Input_File_Name);
  579.  
  580.    if (Options & DISKWRITE)
  581.       printf ("-o%s ", Output_File_Name);
  582.  
  583.    for (i = 0 ; i < Library_Path_Index ; i++)
  584.       printf ("-l%s ", Library_Paths[i]);
  585.  
  586.    printf ("\n");
  587.    }
  588.  
  589. void parse_file_name (File_Name)
  590.   char *File_Name;
  591.   {
  592.   FILE *defaults_file;
  593.   char Option_String[256];
  594.  
  595.   if (++Number_Of_Files > MAX_FILE_NAMES)
  596.     {
  597.     fprintf (stderr, "\nOnly %d file names are allowed in a command line.", 
  598.              MAX_FILE_NAMES);
  599.     exit(1);
  600.     }
  601.  
  602.   if ((defaults_file = fopen(File_Name, "r")) != NULL) {
  603.      while (fgets(Option_String, 256, defaults_file) != NULL)
  604.         read_options(Option_String);
  605.      fclose (defaults_file);
  606.      }
  607.   }
  608.  
  609. void print_stats()
  610.    {
  611.    printf ("                  Statistics\n");
  612.    printf ("                  ----------\n\n");
  613.    printf ("# Rays:  %10ld    # Pixels:  %10ld  # Pixels supersampled: %10ld\n\n",
  614.             Number_Of_Rays, Number_Of_Pixels, Number_Of_Pixels_Supersampled);
  615.  
  616.    printf ("\nIntersection Tests:\n\n");
  617.    printf ("   Type       Tests    Succeeded\n");
  618.    printf ("   ----    ----------  ----------\n\n");
  619.    printf ("  Sphere   %10ld  %10ld\n", Ray_Sphere_Tests, Ray_Sphere_Tests_Succeeded);
  620.    printf ("  Plane    %10ld  %10ld\n", Ray_Plane_Tests, Ray_Plane_Tests_Succeeded);
  621.    printf ("  Triangle %10ld  %10ld\n", Ray_Triangle_Tests, Ray_Triangle_Tests_Succeeded);
  622.    printf ("  Quadric  %10ld  %10ld\n", Ray_Quadric_Tests, Ray_Quadric_Tests_Succeeded);
  623.    printf ("  Quartic  %10ld  %10ld\n", Ray_Quartic_Tests, Ray_Quartic_Tests_Succeeded);
  624.    printf ("  Bounds   %10ld  %10ld\n\n", Bounding_Region_Tests, Bounding_Region_Tests_Succeeded);
  625.    printf ("  Calls to Noise:   %10ld\n", Calls_To_Noise);
  626.    printf ("  Calls to DNoise:  %10ld\n", Calls_To_DNoise);
  627.    printf ("  Shadow Ray Tests: %10ld     Blocking Objects Found:  %10ld\n",
  628.               Shadow_Ray_Tests, Shadow_Rays_Succeeded);
  629.    printf ("  Reflected Rays:   %10ld\n", Reflected_Rays_Traced);
  630.    printf ("  Refracted Rays:   %10ld\n", Refracted_Rays_Traced);
  631.    printf ("  Transmitted Rays: %10ld\n", Transmitted_Rays_Traced);
  632.    }
  633.  
  634. /* Find a file in the search path. */
  635.  
  636. FILE *Locate_File (filename, mode)
  637.    char *filename, *mode;
  638.    {
  639.    FILE *f;
  640.    int i;
  641.    char pathname[FILE_NAME_LENGTH];
  642.  
  643.    /* Check the current directory first. */
  644.    if ((f = fopen (filename, mode)) != NULL)
  645.       return (f);
  646.  
  647.    for (i = 0 ; i < Library_Path_Index ; i++) {
  648.       strcpy (pathname, Library_Paths[i]);
  649.       if (FILENAME_SEPARATOR != NULL)
  650.          strcat (pathname, FILENAME_SEPARATOR);
  651.       strcat (pathname, filename);
  652.       if ((f = fopen (pathname, mode)) != NULL)
  653.          return (f);
  654.       }
  655.  
  656.    return (NULL);
  657.    }
  658.